package gajdulewiczr;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

public class ObjMesh {

	public float[][] vertices;
	public float[][] vnormals;
	public int[][] faces;
	public String name;
	
	float x,y,z;
	float xrot,yrot,zrot;

	public ObjMesh(String fname,float scale,float [] pos, float [] rot) {
		x= pos[0];
		y= pos[1];
		z= pos[2];
		xrot = rot[0];
		yrot = rot[1];
		zrot = rot[2];
		this.initMesh(fname, scale);
		
	}

	private void initMesh(String fname,float scale) {
		String line;
		String[] tokens;
		BufferedReader br = null;
		ArrayList<float[]> verts = new ArrayList<float[]>();
		ArrayList<float[]> vns = new ArrayList<float[]>();
		ArrayList<int[]> fcs = new ArrayList<int[]>();
		int cnt = 0;
		try {
			br = new BufferedReader(new FileReader(fname));
			while (null != (line = br.readLine())) {
				if (line.startsWith("#"))
					continue;
				else if (line.startsWith("g")) {
					this.name = line.split(" ")[1];
				} else if (line.startsWith("v") && !line.startsWith("vn")
						&& !line.startsWith("vt")) {
					tokens = line.split(" ");
					// System.out.println(i++ +"  "+tokens.length);
					verts.add(new float[] { Float.parseFloat(tokens[1])/scale,
							Float.parseFloat(tokens[2])/scale,
							Float.parseFloat(tokens[3])/scale });
					cnt++;
					// System.out.println(cnt);
				} else if (line.startsWith("vn")) {

					tokens = line.split(" ");
					// System.out.println(i++ +"  "+tokens.length);
					vns.add(new float[] { Float.parseFloat(tokens[1]),
							Float.parseFloat(tokens[2]),
							Float.parseFloat(tokens[3]) });
				} else if (line.startsWith("f")) {
					tokens = line.split(" ");
					for (int i = 1; i <= 3; i++) {
						if (tokens[i].indexOf("/") != -1) {
							tokens[i] = tokens[i].substring(0, tokens[i]
									.indexOf('/'));
						}
					}
					fcs.add(new int[] { Integer.parseInt(tokens[1]) - 1,
							Integer.parseInt(tokens[2]) - 1,
							Integer.parseInt(tokens[3]) - 1 });
				} else
					continue;
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {

				e.printStackTrace();
			}
		
		}
		vertices = new float[verts.size()][3];
		faces = new int[fcs.size()][3];
		int i = 0;
		for (Iterator<float[]> iterator = verts.iterator(); iterator.hasNext(); i++) {
			vertices[i] = (float[]) iterator.next();
		}
		i = 0;
		for (Iterator<int[]> iterator = fcs.iterator(); iterator.hasNext(); i++) {
			faces[i] = (int[]) iterator.next();
		}
		this.vnormals = calcVertexNormals();
	}

	private float[][] calcVertexNormals() {
		float[][] ret = new float[vertices.length][3];
		int[] counts = new int[vertices.length];
		float[] v;
		int ind;
		for (int[] f : this.faces) {
			v = calcNormal(f);
			for (int i = 0; i < f.length; i++) {
				ind = f[i];
				if (ret[ind] == null)
					ret[ind] = new float[] { 0.0f, 0.0f, 0.0f };
				ret[ind][0] += v[0];
				ret[ind][1] += v[1];
				ret[ind][2] += v[2];
				counts[ind]++;
			}
		}
		for (int i = 0; i < ret.length; i++) {
			for (int j = 0; j < 3; j++) {
				ret[i][j] /= counts[i];
			}
			ret[i] = normalize(ret[i]);

		}
		return ret;
	}

	private float[] normalize(float[] fs) {
		float total = 0f;
		for (int i = 0; i < fs.length; i++) {
			total += (float) Math.pow(fs[i], 2);
		}
		total = (float) Math.sqrt(total);
		for (int i = 0; i < fs.length; i++) {
			fs[i] /= total;
		}
		return fs;
	}

	private float[] calcNormal(int[] f) {
		float[] v0 = this.vertices[f[0]];
		float[] v1 = this.vertices[f[1]];
		float[] v2 = this.vertices[f[2]];
		float[] a = new float[] { v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2] };
		float[] b = new float[] { v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2] };
		return new float[] { a[1] * b[2] - a[2] * b[1],
				a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] };
	}

	@Override
	public String toString() {
		return String.format("ObjMesh %s #V: %d #Vn: %d #F: %d", this.name,
				this.vertices.length, this.vnormals.length, this.faces.length);
	}

	public static void main(String[] args) {
		ObjMesh m = new ObjMesh("obj/monkey.obj",7f,new float []{0,0,0},new float []{0,0,0});
		System.out.println(m);
		for (int i = 0; i < m.faces.length; i++) {
			if (m.faces[i].length != 3)
				System.out.format("%d: %o", i, m.faces[i].length);
		}
	}

}
